#pragma once

#include "SimpleBehaviour.h"
#include "Point.h"
#include <boost/signals2/signal.hpp>

#include <vector>
#include <map>

namespace game_engine { namespace library
{

/*!
 * \class Flocking
 * \brief 
 */
class Flocking : public game_engine::components::SimpleBehaviour
{
///////////////////////////////////////////////////////////////////////////////
// Attribute definition
///////////////////////////////////////////////////////////////////////////////
public:
    typedef boost::signals2::signal<void ()>  signal_void_void_t;

private:
    utils::Point _currentSpeed;
    utils::Point _nextSpeed;
    utils::Point _collisionTweak;
    vector<GameObject*> _others;
    GameObject* _player;
    vector<GameObject*> _obstacles;
    utils::Point _goalPosition;
    map<Direction,string> _animationId;
    signal_void_void_t _goalReached;
    //FLOAT32 _speed;

    static const utils::Point NULL_POSITION;

///////////////////////////////////////////////////////////////////////////////
// Method definition
///////////////////////////////////////////////////////////////////////////////
public:
    // Constructors and Destructors
    Flocking(void);
    Flocking(GameObject *obj);
    virtual ~Flocking(void);

    // Others
    void onEnter(void) throw(...);
    void onLoop(const FLOAT32 time) throw(...);
    void onExit(void) throw(...);
    boost::signals2::connection connect(signal_void_void_t &publisher, 
        const signal_void_void_t::slot_type &subscriber);

    // Getters
    const utils::Point currentSpeed(void) const;
    const string animationId(const Direction direction) const;
    signal_void_void_t& goalReached(void);
    //const FLOAT32 speed(void) const;

    // Setters
    void setOthers(const vector<GameObject*> others);
    void setPlayer(GameObject *player);
    void setObstacles(const vector<GameObject*> obstacles);
    void setGoalPosition(const utils::Point &goalPosition);
    void setAnimationId(const Direction direction, const string &animId);
    //void setSpeed(const FLOAT32 speed);

private:
    void flockAgainst(void) throw(...);
    void avoid(void) throw(...);
    void goal(void) throw(...);
    utils::Point getObjectPosition(GameObject *obj) throw(...);
    utils::Point getObjectSpeed(GameObject *obj) throw(...);
    const BOOL setNewPosition(const FLOAT32 time) throw(...);
    void setNewSequence(void) throw (...);
    const Direction getDirectionFromAngle(const FLOAT32 a) const;

};

}}
